<!DOCTYPE HTML>
<HTML lang="zh-CN">
	<HEAD>
		<TITLE>马里奥</TITLE>
		<meta charset="UTF-8">
		<style type="text/css">
			*body {
				margin: 0 auto;
			}

			#status {
				position: absolute;
				left: 50%;
				top: 170px;
				margin-left: 60px;
			}

			.background {
				background: rgb(52, 166, 251);
				table-layout: fixed;
				border-spacing: 0;
			}

			.background td {
				padding: 0;
			}

			.lava {
				background: rgb(255, 100, 100);
			}

			.wall {
				background: white;
			}

			.actor {
				position: absolute;
			}

			.coin {
				background: rgb(241, 229, 89);
			}

			.player {
				background: rgb(64, 64, 64);
			}

			.lost .player {
				background: rgb(160, 64, 64);
			}

			.won .player {
				box-shadow: -4px -7px 8px white, 4px -7px 8px white;
			}

			.game {
				overflow: hidden;
				max-width: 600px;
				max-height: 450px;
				position: relative;
			}
		</style>
	</head>

	<body>
		<!--<img style="position: absolute;right: 0;top: 0;" src=" http://a4.qpic.cn/psb?/V13id91S0o4nYt/y9R.1dX5WxfYfZzDqBMG2hsjLT7LiZjPoCPYg.6gxhk!/b/dEMBAAAAAAAA&ek=1&kp=1&pt=0&bo=LAGyAQAAAAARF74!&vuin=206105759&tm=1522486800&sce=60-2-2&rf=viewer_4">-->
		<div id='status'>你还剩余 <span id="lives"></span> 条生命</div>
		<script type="text/javascript">
			/*
Based on Dark Blue by Thomas Palef.
Plans are submitted as an array of strings that forms a grid.
@ = Player start position
o = Coins
x = Solid surfaces
! = Non-moving lava
= = Vertical moving lava
v = Dripping lava
| = Horizontal moving lava
*/
			var simpleLevelPlan = [
				"                      ",
				"                      ",
				"  x              = x  ",
				"  x         o o    x  ",
				"  x @      xxxxx   x  ",
				"  xxxxx            x  ",
				"      x!!!!!!!!!!!!x  ",
				"      xxxxxxxxxxxxxx  ",
				"                      "
			];

			var GAME_LEVELS = [
				["                                                                                ",
					"                                                                                ",
					"                                                                                ",
					"                                                                                ",
					"                                                                                ",
					"                                                                                ",
					"                                                                  xxx           ",
					"                                                   xx      xx    xx!xx          ",
					"                                    o o      xx                  x!!!x          ",
					"                                                                 xx!xx          ",
					"                                   xxxxx                          xxx           ",
					"                                                                            xx  ",
					"  xx                                      o o                                x  ",
					"  x                     o                                                    x  ",
					"  x                                      xxxxx                             o x  ",
					"  x          xxxx       o      ooo                                           x  ",
					"  x  @       x  x                                                xxxxx       x  ",
					"  xxxxxxxxxxxx  xxxxxxxxxxxxxxx   xxxxxxxxxxxxxxxxxxxx     xxxxxxx   xxxxxxxxx  ",
					"                              x   x                  x     x                    ",
					"                              x   x                  xooooox                    ",
					"                              x ! x                  xooooox                    ",
					"                              xxxxx                  xxxxxxx                    ",
					"                                                                                ",
					"                                                                                "
				],
				["                                      x!!x                        xxxxxxx                                    x!x  ",
					"                                      x!!x                     xxxx     xxxx                                 x!x  ",
					"                                      x!!xxxxxxxxxx           xx           xx                                x!x  ",
					"                                      xx!!!!!!!!!!xx         xx             xx                               x!x  ",
					"                                       xxxxxxxxxx!!x         x                                    o   o   o  x!x  ",
					"                                                xx!x         x     o   o                                    xx!x  ",
					"                                                 x!x         x                                xxxxxxxxxxxxxxx!!x  ",
					"                                                 xvx         x     x   x                        !!!!!!!!!!!!!!xx  ",
					"                                                             xx  |   |   |  xx            xxxxxxxxxxxxxxxxxxxxx   ",
					"                                                              xx!!!!!!!!!!!xx            v                        ",
					"                                                               xxxx!!!!!xxxx                                      ",
					"                                               x     x            xxxxxxx        xxx         xxx                  ",
					"                                               x     x                           x x         x x                  ",
					"                                               x     x                             x         x                    ",
					"                                               x     x                             xx        x                    ",
					"                                               xx    x                             x         x                    ",
					"                                               x     x      o  o     x   x         x         x                    ",
					"               xxxxxxx        xxx   xxx        x     x               x   x         x         x                    ",
					"              xx     xx         x   x          x     x     xxxxxx    x   x   xxxxxxxxx       x                    ",
					"             xx       xx        x o x          x    xx               x   x   x               x                    ",
					"     @       x         x   x    x   x          x     x               x   x   x               x                    ",
					"    xxx      x         x        x   x          x     x               x   xxxxx   xxxxxx      x                    ",
					"    x x      x         x       xx o xx         x     x               x     o     x x         x                    ",
					"!!!!x x!!!!!!x         x      xx     xx!!!!!!!!xx    x!!!!!!!!!!     x     =     x x         x                    ",
					"!!!!x x!!!!!!x         x!!!!!xx       xxxxxxxxxx     x!!!!!!!xx!     xxxxxxxxxxxxx xx  o o  xx                    ",
					"!!!!x x!!!!!!x         x!!!!!x    o                 xx!!!!!!xx !                    xx     xx                     ",
					"!!!!x x!!!!!!x         x!!!!!x                     xx!!!!!!xx  !                     xxxxxxx                      ",
					"!!!!x x!!!!!!x         x!!!!!xx       xxxxxxxxxxxxxx!!!!!!xx   !                                                  ",
					"!!!!x x!!!!!!x         x!!!!!!xxxxxxxxx!!!!!!!!!!!!!!!!!!xx    !                                                  ",
					"!!!!x x!!!!!!x         x!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!xx     !                                                  "
				],
				["                                                                                                              ",
					"                                                                                                              ",
					"                                                                                                              ",
					"                                                                                                              ",
					"                                                                                                              ",
					"                                        o                                                                     ",
					"                                                                                                              ",
					"                                        x                                                                     ",
					"                                        x                                                                     ",
					"                                        x                                                                     ",
					"                                        x                                                                     ",
					"                                       xxx                                                                    ",
					"                                       x x                 !!!        !!!  xxx                                ",
					"                                       x x                 !x!        !x!                                     ",
					"                                     xxx xxx                x          x                                      ",
					"                                      x   x                 x   oooo   x       xxx                            ",
					"                                      x   x                 x          x      x!!!x                           ",
					"                                      x   x                 xxxxxxxxxxxx       xxx                            ",
					"                                     xx   xx      x   x      x                                                ",
					"                                      x   xxxxxxxxx   xxxxxxxx              x x                               ",
					"                                      x   x           x                    x!!!x                              ",
					"                                      x   x           x                     xxx                               ",
					"                                     xx   xx          x                                                       ",
					"                                      x   x= = = =    x            xxx                                        ",
					"                                      x   x           x           x!!!x                                       ",
					"                                      x   x    = = = =x     o      xxx       xxx                              ",
					"                                     xx   xx          x                     x!!!x                             ",
					"                              o   o   x   x           x     x                xxv        xxx                   ",
					"                                      x   x           x              x                 x!!!x                  ",
					"                             xxx xxx xxx xxx     o o  x!!!!!!!!!!!!!!x                   vx                   ",
					"                             x xxx x x xxx x          x!!!!!!!!!!!!!!x                                        ",
					"                             x             x   xxxxxxxxxxxxxxxxxxxxxxx                                        ",
					"                             xx           xx                                         xxx                      ",
					"  xxx                         x     x     x                                         x!!!x                xxx  ",
					"  x x                         x    xxx    x                                          xxx                 x x  ",
					"  x                           x    xxx    xxxxxxx                        xxxxx                             x  ",
					"  x                           x           x                              x   x                             x  ",
					"  x                           xx          x                              x x x                             x  ",
					"  x                                       x       |xxxx|    |xxxx|     xxx xxx                             x  ",
					"  x                xxx             o o    x                              x         xxx                     x  ",
					"  x               xxxxx       xx          x                             xxx       x!!!x          x         x  ",
					"  x               oxxxo       x    xxx    x                             x x        xxx          xxx        x  ",
					"  x                xxx        xxxxxxxxxxxxx  x oo x    x oo x    x oo  xx xx                    xxx        x  ",
					"  x      @          x         x           x!!x    x!!!!x    x!!!!x    xx   xx                    x         x  ",
					"  xxxxxxxxxxxxxxxxxxxxxxxxxxxxx           xxxxxxxxxxxxxxxxxxxxxxxxxxxxx     xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx  ",
					"                                                                                                              ",
					"                                                                                                              "
				],
				["                                                                                                  xxx x       ",
					"                                                                                                      x       ",
					"                                                                                                  xxxxx       ",
					"                                                                                                  x           ",
					"                                                                                                  x xxx       ",
					"                          o                                                                       x x x       ",
					"                                                                                             o o oxxx x       ",
					"                   xxx                                                                                x       ",
					"       !  o  !                                                xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxx       ",
					"       x     x                                                x   x x   x x   x x   x x   x x   x x           ",
					"       x= o  x            x                                   xxx x xxx x xxx x xxx x xxx x xxx x xxxxx       ",
					"       x     x                                                  x x   x x   x x   x x   x x   x x     x       ",
					"       !  o  !            o                                  xxxx xxxxx xxxxx xxxxx xxxxx xxxxx xxxxxxx       ",
					"                                                                                                              ",
					"          o              xxx                              xx                                                  ",
					"                                                                                                              ",
					"                                                                                                              ",
					"                                                      xx                                                      ",
					"                   xxx         xxx                                                                            ",
					"                                                                                                              ",
					"                          o                                                     x      x                      ",
					"                                                          xx     xx                                           ",
					"             xxx         xxx         xxx                                 x                  x                 ",
					"                                                                                                              ",
					"                                                                 ||                                           ",
					"  xxxxxxxxxxx                                                                                                 ",
					"  x         x o xxxxxxxxx o xxxxxxxxx o xx                                                x                   ",
					"  x         x   x       x   x       x   x                 ||                  x     x                         ",
					"  x  @      xxxxx   o   xxxxx   o   xxxxx                                                                     ",
					"  xxxxxxx                                     xxxxx       xx     xx     xxx                                   ",
					"        x=                  =                =x   x                     xxx                                   ",
					"        xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx   x!!!!!!!!!!!!!!!!!!!!!xxx!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!",
					"                                                  xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
					"                                                                                                              "
				]
			];

			// Assumes the plan is valid (add validation for production)
			function Level(plan) {
				this.width = plan[0].length;
				this.height = plan.length;
				// Array of arrays, each position containing null or a character
				this.grid = [];
				// Contains all of the dynamic objects (lava, coin or player),
				// along with their position and state
				this.actors = [];

				for (var y = 0; y < this.height; y++) {
					var line = plan[y],
						gridLine = [];
					for (var x = 0; x < this.width; x++) {
						var ch = line[x],
							fieldType = null;
						var Actor = actorChars[ch];
						if (Actor)
							// This constructs the referenced moving object in
							// actorChars and pushes it to the actors array
							this.actors.push(new Actor(new Vector(x, y), ch));
						else if (ch == 'x')
							// Wall
							fieldType = 'wall';
						else if (ch == '!')
							// Stationary lava
							fieldType = 'lava';
						gridLine.push(fieldType);
					}
					this.grid.push(gridLine);
				}
				// Find the Player actor
				this.player = this.actors.filter(function(actor) {
					return actor.type == 'player';
				})[0];
				// Track whether the player has won or lost;
				// finishDelay keeps the level active for a brief period of time
				this.status = this.finishDelay = null;
			}
			// Figure out if the level is finished
			Level.prototype.isFinished = function() {
				return this.status != null && this.finishDelay < 0;
			};
			// Figure out the collision area of an actor
			Level.prototype.obstacleAt = function(pos, size) {
				var xStart = Math.floor(pos.x);
				var xEnd = Math.ceil(pos.x + size.x);
				var yStart = Math.floor(pos.y);
				var yEnd = Math.ceil(pos.y + size.y);

				// The upper and side bounds of the level return a wall
				if (xStart < 0 || xEnd > this.width || yStart < 0)
					return 'wall';
				// The bottom bound returns lava
				if (yEnd > this.height)
					return 'lava';
				// Check what's on the grid around the collision box
				for (var y = yStart; y < yEnd; y++) {
					for (var x = xStart; x < xEnd; x++) {
						var fieldType = this.grid[y][x];
						// returns 'wall' or 'lava'
						if (fieldType) return fieldType;
					}
				}
			};
			// Track what actors overlap a given actor
			Level.prototype.actorAt = function(actor) {
				for (var i = 0; i < this.actors.length; i++) {
					var other = this.actors[i];
					if (other != actor &&
						actor.pos.x + actor.size.x > other.pos.x &&
						actor.pos.x < other.pos.x + other.size.x &&
						actor.pos.y + actor.size.y > other.pos.y &&
						actor.pos.y < other.pos.y + other.size.y)
						return other;
				}
			};
			// Time increment for Level.animate()
			var maxStep = 0.05;
			// Animate the level
			// step will be given in seconds, keys is an object that
			// contains info about the arrow keys the player has pressed.
			Level.prototype.animate = function(step, keys) {
				// Used for the delay at the end of a game
				if (this.status != null)
					this.finishDelay -= step;

				while (step > 0) {
					var thisStep = Math.min(step, maxStep);
					this.actors.forEach(function(actor) {
						actor.act(thisStep, this, keys);
					}, this);
					step -= thisStep;
				}
			};
			// Handle collisions between actors
			Level.prototype.playerTouched = function(type, actor) {
				// Lava's been touched
				if (type == 'lava' && this.status == null) {
					this.status = 'lost';
					this.finishDelay = 1;
				} else if (type == 'coin') { // a coin's been touched
					// Remove the coin that's been collected from actors array
					this.actors = this.actors.filter(function(other) {
						return other != actor;
					});
					// No more coins = you've won
					if (!this.actors.some(function(actor) {
							return actor.type == 'coin';
						})) {
						this.status = 'won';
						this.finishDelay = 1;
					}
				}
			}

			var actorChars = {
				'@': Player,
				'o': Coin,
				'=': Lava,
				'|': Lava,
				'v': Lava
			};

			// Vector stores the position and size of an actor
			function Vector(x, y) {
				this.x = x;
				this.y = y;
			}
			Vector.prototype.plus = function(other) {
				return new Vector(this.x + other.x, this.y + other.y);
			}
			Vector.prototype.times = function(factor) {
				return new Vector(this.x * factor, this.y * factor);
			}

			// Player constructor
			function Player(pos) {
				// This properly aligns the bottom of the player
				// to the square below (adjusts for player height)
				this.pos = pos.plus(new Vector(0, -0.5));
				this.size = new Vector(0.8, 1.5);
				this.speed = new Vector(0, 0);
			}
			Player.prototype.type = 'player';
			// X and Y movement are handled independently because
			// a wall shouldn't stop the up and down motion of jumping
			// and a floor shouldn't stop side to side movement
			var playerXSpeed = 7;
			Player.prototype.moveX = function(step, level, keys) {
				this.speed.x = 0;
				if (keys.left) this.speed.x -= playerXSpeed;
				if (keys.right) this.speed.x += playerXSpeed;

				var motion = new Vector(this.speed.x * step, 0);
				var newPos = this.pos.plus(motion);
				var obstacle = level.obstacleAt(newPos, this.size);
				if (obstacle)
					level.playerTouched(obstacle);
				else
					this.pos = newPos;
			};
			var gravity = 30;
			var jumpSpeed = 17;
			Player.prototype.moveY = function(step, level, keys) {
				this.speed.y += step * gravity;
				var motion = new Vector(0, this.speed.y * step);
				var newPos = this.pos.plus(motion);
				var obstacle = level.obstacleAt(newPos, this.size);
				if (obstacle) {
					level.playerTouched(obstacle);
					if (keys.up && this.speed.y > 0)
						this.speed.y = -jumpSpeed;
					else
						this.speed.y = 0;
				} else {
					this.pos = newPos;
				}
			};
			Player.prototype.act = function(step, level, keys) {
				this.moveX(step, level, keys);
				this.moveY(step, level, keys);

				var otherActor = level.actorAt(this);
				if (otherActor)
					level.playerTouched(otherActor.type, otherActor);

				// Losing animation
				if (level.status == 'lost') {
					this.pos.y += step;
					this.size.y -= step;
				}
			};

			// Lava constructor
			function Lava(pos, ch) {
				this.pos = pos;
				this.size = new Vector(1, 1);
				if (ch == "=") {
					// I'm guessing that speed will be added to this.pos
					// in a moving method added later
					this.speed = new Vector(2, 0);
				} else if (ch == '|') {
					this.speed = new Vector(0, 2);
				} else if (ch == 'v') {
					this.speed = new Vector(0, 3);
					this.repeatPos = pos;
				}
			}
			Lava.prototype.type = 'lava';
			// Action
			Lava.prototype.act = function(step, level) {
				var newPos = this.pos.plus(this.speed.times(step));
				if (!level.obstacleAt(newPos, this.size))
					this.pos = newPos;
				else if (this.repeatPos)
					this.pos = this.repeatPos;
				else
					this.speed = this.speed.times(-1);
			};

			// Coin constructor
			function Coin(pos) {
				this.basePos = this.pos = pos.plus(new Vector(0.2, 0.1));
				this.size = new Vector(0.6, 0.6);
				this.wobble = Math.random() * Math.PI * 2;
			}
			Coin.prototype.type = 'coin';
			var wobbleSpeed = 8,
				wobbleDist = 0.07;
			// Action
			Coin.prototype.act = function(step) {
				this.wobble += step * wobbleSpeed;
				var wobblePos = Math.sin(this.wobble) * wobbleDist;
				this.pos = this.basePos.plus(new Vector(0, wobblePos));
			};

			// Helper function that creates an element
			// and gives it a class
			function elt(name, className) {
				var elt = document.createElement(name);
				if (className) elt.className = className;
				return elt;
			}

			// Tracking keypresses for player movement
			var arrowCodes = {
				37: 'left',
				38: 'up',
				39: 'right'
			};

			function trackKeys(codes) {
				var pressed = Object.create(null);

				function handler(event) {
					if (codes.hasOwnProperty(event.keyCode)) {
						var down = event.type == 'keydown';
						pressed[codes[event.keyCode]] = down;
						event.preventDefault();
					}
				}
				addEventListener('keydown', handler);
				addEventListener('keyup', handler);

				pressed.unregister = function() {
					removeEventListener('keydown', handler);
					removeEventListener('keyup', handler);
				};

				return pressed;
			}

			// Run the animation
			function runAnimation(frameFunc) {
				var lastTime = null;

				function frame(time) {
					var stop = false;
					if (lastTime != null) {
						var timeStep = Math.min(time - lastTime, 100) / 1000;
						stop = frameFunc(timeStep) === false;
					}
					lastTime = time;
					if (!stop)
						requestAnimationFrame(frame);
				}
				requestAnimationFrame(frame);
			}

			// Run the level
			var arrows = trackKeys(arrowCodes);

			function runLevel(level, Display, andThen) {
				var display = new Display(document.body, level);
				// Used for storing pause state of the game
				var running = 'yes';

				function handleKey(event) {
					if (event.keyCode == 27) {
						if (running == 'no') {
							running = 'yes';
							runAnimation(animation);
						} else if (running == 'pausing') {
							running = 'yes';
						} else if (running == 'yes') {
							running = 'pausing';
						}
					}
				}
				addEventListener('keydown', handleKey);

				function animation(step) {
					if (running == 'pausing') {
						running = 'no';
						return false;
					}

					level.animate(step, arrows);
					display.drawFrame(step);
					if (level.isFinished()) {
						display.clear();
						// Remove the watch on the esc key 
						//removeEventListener('keydown', handleKey);
						// Unregister the arrow key listeners
						//arrows.unregister();
						if (andThen)
							andThen(level.status);
						return false;
					}
				}

				runAnimation(animation);
			}

			// Run the game
			function runGame(plans, Display) {
				var lives = 114514;
				var livesSpan = document.getElementById('lives');
				var gameStatus = document.getElementById('status');

				function startLevel(n) {
					livesSpan.textContent = lives;
					runLevel(new Level(plans[n]), Display, function(status) {
						if (status == 'lost') {
							lives--;
							if (lives == 0) {
								gameStatus.textContent = 'Game Over';
								console.log('Game over');
							} else
								startLevel(n);
						} else if (n < plans.length - 1)
							startLevel(n + 1);
						else
							console.log('You win!');
					});
				}
				startLevel(0);
			}


			// DOMDisplay uses the DOM to draw the program out
			function DOMDisplay(parent, level) {
				this.wrap = parent.appendChild(elt('div', 'game'));
				this.level = level;

				// Background is drawn only once
				this.wrap.appendChild(this.drawBackground());
				// The actorLayer is animated in the drawFrame() method
				this.actorLayer = null;
				this.drawFrame();
			}
			// Set the scale of 1 grid unit
			var scale = 20;
			// Draw the background
			DOMDisplay.prototype.drawBackground = function() {
				var table = elt('table', 'background');
				table.style.width = this.level.width * scale + 'px';
				this.level.grid.forEach(function(row) {
					var rowElt = table.appendChild(elt('tr'));
					rowElt.style.height = scale + 'px';
					row.forEach(function(type) {
						rowElt.appendChild(elt('td', type));
					});
				});
				return table;
			};
			// Draw the actors
			DOMDisplay.prototype.drawActors = function() {
				var wrap = elt('div');
				this.level.actors.forEach(function(actor) {
					var rect = wrap.appendChild(elt('div', 'actor ' + actor.type));
					rect.style.width = actor.size.x * scale + 'px';
					rect.style.height = actor.size.y * scale + 'px';
					rect.style.left = actor.pos.x * scale + 'px';
					rect.style.top = actor.pos.y * scale + 'px';
				});
				return wrap;
			};
			// Redraw the actors
			DOMDisplay.prototype.drawFrame = function() {
				if (this.actorLayer)
					this.wrap.removeChild(this.actorLayer);
				this.actorLayer = this.wrap.appendChild(this.drawActors());
				// The status class is used to style the player based on
				// the state of the game (won or lost)
				this.wrap.className = 'game ' + (this.level.status || '');
				this.scrollPlayerIntoView();
			};
			// Make sure the player's always on screen
			DOMDisplay.prototype.scrollPlayerIntoView = function() {
				var width = this.wrap.clientWidth;
				var height = this.wrap.clientHeight;
				var margin = width / 3;

				// The viewport
				var left = this.wrap.scrollLeft,
					right = left + width;
				var top = this.wrap.scrollTop,
					bottom = top + height;

				// center makes use of the Vector methods defined earlier
				var player = this.level.player;
				var center = player.pos.plus(player.size.times(0.5))
					.times(scale);

				if (center.x < left + margin)
					this.wrap.scrollLeft = center.x - margin;
				else if (center.x > right - margin)
					this.wrap.scrollLeft = center.x + margin - width;
				if (center.y < top + margin)
					this.wrap.scrollTop = center.y - margin;
				else if (center.y > bottom - margin)
					this.wrap.scrollTop = center.y + margin - height;
			}
			// Clear the level
			DOMDisplay.prototype.clear = function() {
				this.wrap.parentNode.removeChild(this.wrap);
			};

			// Canvas API helper function
			function flipHorizontally(context, around) {
				context.translate(around, 0);
				context.scale(-1, 1);
				context.translate(-around, 0);
			}
			// Use Canvas API to draw game
			function CanvasDisplay(parent, level) {
				// Set up the canvas element
				this.canvas = document.createElement('canvas');
				this.canvas.width = Math.min(1000, level.width * scale);
				this.canvas.height = Math.min(1000, level.height * scale);
				this.canvas.style.display = 'block';
				this.canvas.style.margin = '200px auto 0';
				parent.appendChild(this.canvas);
				this.cx = this.canvas.getContext('2d');

				this.level = level;
				// Uses the step size passed to drawFrame()
				this.animationTime = 0;
				this.flipPlayer = false;

				this.viewport = {
					left: 0,
					top: 0,
					width: this.canvas.width / scale,
					height: this.canvas.height / scale
				};

				this.drawFrame(0);
			}
			CanvasDisplay.prototype.clear = function() {
				this.canvas.parentNode.removeChild(this.canvas);
			};
			// Draw the frame
			CanvasDisplay.prototype.drawFrame = function(step) {
				this.animationTime += step;

				// Update the current player position for the viewport
				this.updateViewport();
				// Clear current frame
				this.clearDisplay();
				// Draw the background
				this.drawBackground();
				// Draw the actors
				this.drawActors();
			};
			// Scrolls the viewport depending on the player position
			CanvasDisplay.prototype.updateViewport = function() {
				var view = this.viewport,
					margin = view.width / 3;
				var player = this.level.player;
				var center = player.pos.plus(player.size.times(0.5));

				// Compare the center.x of player to the viewport
				// Player is less than the left of the viewport plus margin
				if (center.x < view.left + margin)
					// Scroll left until less than 0
					view.left = Math.max(center.x - margin, 0);
				// Player is further right than the right of the viewport plus margin
				else if (center.x > view.left + view.width - margin)
					// Scroll right until greater than the edge of the level
					view.left = Math.min(center.x + margin - view.width,
						this.level.width - view.width);
				if (center.y < view.top + margin)
					view.top = Math.max(center.y - margin, 0);
				else if (center.y > view.top + view.height - margin)
					view.top = Math.min(center.y + margin - view.height,
						this.level.height - view.height);
			};
			CanvasDisplay.prototype.clearDisplay = function() {
				if (this.level.status == 'won')
					this.cx.fillStyle = 'rgb(68, 191, 255)';
				else if (this.level.status == 'lost')
					this.cx.fillStyle = 'rgb(44, 136, 214)';
				else
					this.cx.fillStyle = 'rgb(52, 166, 251)';
				this.cx.fillRect(0, 0,
					this.canvas.width, this.canvas.height);
			};
			var otherSprites = document.createElement('img');
			otherSprites.src = 'http://eloquentjavascript.net/img/sprites.png';
			// Draw the background
			CanvasDisplay.prototype.drawBackground = function() {
				var view = this.viewport;
				var xStart = Math.floor(view.left);
				var xEnd = Math.ceil(view.left + view.width);
				var yStart = Math.floor(view.top);
				var yEnd = Math.ceil(view.top + view.height);

				for (var y = yStart; y < yEnd; y++) {
					for (var x = xStart; x < xEnd; x++) {
						var tile = this.level.grid[y][x];
						if (tile == null) continue;
						var screenX = (x - view.left) * scale;
						var screenY = (y - view.top) * scale;
						var tileX = tile == 'lava' ? scale : 0;
						this.cx.drawImage(otherSprites,
							tileX, 0, scale, scale,
							screenX, screenY, scale, scale);
					}
				}
			};
			// Draw the player (called by drawActors())
			var playerSprites = document.createElement('img');
			playerSprites.src = 'http://eloquentjavascript.net/img/player.png';
			var playerXOverlap = 4;
			CanvasDisplay.prototype.drawPlayer = function(x, y, width, height) {
				var sprite = 8,
					player = this.level.player;
				width += playerXOverlap * 2;
				x -= playerXOverlap;
				if (player.speed.x != 0)
					this.flipPlayer = player.speed.x < 0;

				if (player.speed.y != 0)
					sprite = 9;
				else if (player.speed.x != 0)
					sprite = Math.floor(this.animationTime * 12) % 8;

				this.cx.save();
				if (this.flipPlayer)
					flipHorizontally(this.cx, x + width / 2);

				this.cx.drawImage(playerSprites,
					sprite * width, 0, width, height,
					x, y, width, height);
				this.cx.restore();
			}
			// Draw the actors
			CanvasDisplay.prototype.drawActors = function() {
				this.level.actors.forEach(function(actor) {
					var width = actor.size.x * scale;
					var height = actor.size.y * scale;
					var x = (actor.pos.x - this.viewport.left) * scale;
					var y = (actor.pos.y - this.viewport.top) * scale;
					if (actor.type == 'player') {
						this.drawPlayer(x, y, width, height);
					} else {
						var tileX = (actor.type == 'coin' ? 2 : 1) * scale;
						this.cx.drawImage(otherSprites,
							tileX, 0, width, height,
							x, y, width, height);
					}
				}, this);
			};


			// Run game with DOMDisplay
			// runGame(GAME_LEVELS, DOMDisplay);

			// Run game with CanvasDisplay
			runGame(GAME_LEVELS, CanvasDisplay);
		</script>

	</body>
</html>
